﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Nirvana
{
    /// <summary>
    /// Ab加载模拟器类：用于在Editor模式下启动加载本地ab文件运行
    /// </summary>
    public sealed class AssetSimulator 
    {
        private const string modename = "SimulateAssetBundleMode";
        private const string resultname = "SimulateAssetBundleFailed";
        private int modeId =  -1;
        private int result = -1;
        private int assetbundleId = -1;
        private float minDetalTime = 0;
        private float maxDetalTime = 1;
        public int SimulateLoadModelInEditor
        {
            get
            {
#if UNITY_EDITOR
                if(this.modeId == -1)
                {
                    this.modeId = EditorPrefs.GetInt(modename, 1);
                }
#endif
                return modeId;
            }
            set
            {

                if (this.modeId != value)
                {
                    this.modeId = value;
#if UNITY_EDITOR
                    EditorPrefs.SetInt(modename, value);
#endif
                }
            }
        }

        public bool SimulateAssetBundleFailed
        {
            get
            {
#if UNITY_EDITOR
                if (this.result < 0)
                {
                    this.result = ((!EditorPrefs.GetBool("SimulateAssetBundleFailed", false)) ? 0 : 1);
                }
#endif
                return result > 0;
            }
            set
            {
                bool flag = this.result > 0;
                if (flag != value)
                {
                    this.result = ((!value) ? 0 : 1);
#if UNITY_EDITOR
                    EditorPrefs.SetBool("SimulateAssetBundleFailed", value);
#endif
                }

            }
        }

        public bool SimulateAssetBundle
        {
            get
            {
                if(this.assetbundleId < 0)
                {
                    this.Reset();
                }
                return this.assetbundleId > 0;
            }
        }

        private float GetMinDetalTime()
        {
            if (this.minDetalTime < 0) Reset();
            return this.minDetalTime;
        }

        private float GetMaxDetalTime()
        {
            if (this.maxDetalTime < 0) Reset();
            return this.maxDetalTime;
        }

        private void Reset()
        {
            switch (this.SimulateLoadModelInEditor)
            {
                case 0:
                    this.assetbundleId = 0;
                    this.minDetalTime = 0;
                    this.maxDetalTime = 0;
                    break;
                case 1:
                    this.assetbundleId = 1;
                    this.minDetalTime = 0;
                    this.maxDetalTime = 0;
                    break;
                case 2:
                    this.assetbundleId =1;
                    this.minDetalTime = 0;
                    this.maxDetalTime = 0.1f;
                    break;
                case 3:
                    this.assetbundleId = 1;
                    this.minDetalTime = 0;
                    this.maxDetalTime = 0.5f;
                    break;
                case 4:
                    this.assetbundleId = 1;
                    this.minDetalTime = 0.5f;
                    this.maxDetalTime = 0.5f;
                    break;

            }
        }

        public WaitLoadObjectTimer WaitLoadObject()
        {
            return new WaitLoadObjectTimer(null, UnityEngine.Random.Range(this.GetMinDetalTime(), this.GetMaxDetalTime()));
        }

        public WaitForSecondsRealtime WaitTimeForFailed()
        {
            if (!this.SimulateAssetBundleFailed)
            {
                return null;
            }
            if(UnityEngine.Random.Range(0,100)<= 50)
            {
                return new WaitForSecondsRealtime(UnityEngine.Random.Range(1f, 5f));
            }
            return null;
        }

#if UNITY_EDITOR
        public UnityEngine.Object LoadObject(string bundlename,string assetname,Type type)
        {
            //在指定assetbundle名称中找对应资源
            string[] assetnames = AssetDatabase.GetAssetPathsFromAssetBundleAndAssetName(bundlename, Path.GetFileNameWithoutExtension(assetname));
            string path = null;
            if (Path.HasExtension(assetname))
            {
                string filename = Path.GetFileNameWithoutExtension(assetname);
                string extname = Path.GetExtension(assetname);
                foreach(var s in assetnames)
                {
                    string curFileName = Path.GetFileNameWithoutExtension(s);
                    string curExtName = Path.GetExtension(s);
                    if(curFileName == filename && curExtName == extname)
                    {
                        path = s;
                        break;
                    }
                }
            }else if(assetnames.Length > 0)
            {
                string filename = Path.GetFileNameWithoutExtension(assetname);
                foreach (var s in assetnames)
                {
                    string curFileName = Path.GetFileNameWithoutExtension(s);
                    if (curFileName == filename)
                    {
                        path = s;
                        break;
                    }
                }
            }

            if(path == null)
            {
                return null;
            }
            return AssetDatabase.LoadAssetAtPath(path, type);
        }


        public WaitLoadObjectTimer LoadAsync(string bundlename, string assetname, Type type)
        {
            UnityEngine.Object obj = this.LoadObject(bundlename, assetname, type);
            float time = UnityEngine.Random.Range(this.GetMinDetalTime(), this.GetMaxDetalTime());
            if(obj == null)
            {
                return new WaitLoadObjectTimer("Load object {0}:{1} failed.", new object[]
                {
                    bundlename,
                    assetname
                });
            }
            return new WaitLoadObjectTimer(obj, time);
        }

        public WaitLoadObjectTimer Load(string bundlename, string assetname, Type type)
        {
            UnityEngine.Object obj = this.LoadObject(bundlename, assetname, type);
            if (obj == null)
            {
                return new WaitLoadObjectTimer("Load object {0}:{1} failed.", new object[]
                {
                    bundlename,
                    assetname
                });
            }
            return new WaitLoadObjectTimer(obj, 0f);
        }

        public WaitLoadSceneProgressAsync LoadSceneAsync(string bundlename, string assetname, LoadSceneMode scenemode)
        {
            float time = UnityEngine.Random.Range(this.GetMinDetalTime(), this.GetMaxDetalTime());
            return new WaitLoadSceneProgressAsync(bundlename, assetname, scenemode,time);
        }

        public WaitLoadSceneProgress LoadScene(string bundlename, string assetname, LoadSceneMode scenemode)
        {
            return new WaitLoadSceneProgress(bundlename, assetname, scenemode);
        }
#endif
    }
}

